#include <jni.h>
#include <string>
#include <dlfcn.h>
#include "dalvik.h"
#include "art_method.h"

extern "C"
JNIEXPORT void JNICALL
Java_com_aruba_andfixapplication_DexManager_replace(JNIEnv *env, jobject instance, jint sdk,
                                                    jobject bug_methodMethod,
                                                    jobject fix_methodMethod,
                                                    jclass fix_methodClazz) {
    //第一步，根据java中的Method，获取native层中的Method指针
    Method *bug_method = (Method *) env->FromReflectedMethod(bug_methodMethod);
    Method *fix_method = (Method *) env->FromReflectedMethod(fix_methodMethod);

    //第二步，找到ClassObject
    //获取dalvik虚拟机动态链接库的句柄
    void *dvm_hand = dlopen("libdvm.so", RTLD_NOW);
    //利用hook，获取so库中的方法
    typedef Object *(*FindObject)(void *thread, jobject jobject1);
    typedef void *(*FindThread)();
    //该函数为根据方法返回ClassObject，需要两个参数，1：虚拟机线程 2：class对象
    FindObject findObject = (FindObject) dlsym(dvm_hand, sdk > 10 ?
                                                         "_Z20dvmDecodeIndirectRefP6ThreadP8_jobject"
                                                                  :
                                                         "dvmDecodeIndirectRef");;
    //该函数返回虚拟机线程
    FindThread findThread = (FindThread) dlsym(dvm_hand,
                                               sdk > 10 ? "_Z13dvmThreadSelfv" : "dvmThreadSelf");

    //找到ClassObject，将status变为CLASS_INITIALIZED
    ClassObject *firstFiled = (ClassObject *) findObject(findThread(), fix_methodClazz);
    firstFiled->status = CLASS_INITIALIZED;

    //第三步，改变method指针
    bug_method->accessFlags |= ACC_PUBLIC;
    bug_method->methodIndex = fix_method->methodIndex;
    bug_method->jniArgInfo = fix_method->jniArgInfo;
    bug_method->registersSize = fix_method->registersSize;
    bug_method->outsSize = fix_method->outsSize;
    //方法参数 原型
    bug_method->prototype = fix_method->prototype;
    bug_method->insns = fix_method->insns;
    bug_method->nativeFunc = fix_method->nativeFunc;
}

extern "C"
JNIEXPORT void JNICALL
Java_com_aruba_andfixapplication_DexManager_replaceArt(JNIEnv *env, jobject instance,
                                                       jobject wrongMethod, jobject rightMethod) {
//    art虚拟机替换  art  ArtMethod  ---》Java方法
    art::mirror::ArtMethod *wrong = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            wrongMethod);
    art::mirror::ArtMethod *right = (art::mirror::ArtMethod *) env->FromReflectedMethod(
            rightMethod);

    wrong->declaring_class_ = right->declaring_class_;

    wrong->dex_code_item_offset_ = right->dex_code_item_offset_;
    wrong->dex_cache_resolved_methods_ = right->dex_cache_resolved_methods_;
    wrong->dex_cache_resolved_types_ = right->dex_cache_resolved_types_;
    wrong->access_flags_ = right->access_flags_;
    wrong->method_index_ = right->method_index_;
    wrong->dex_method_index_ = right->dex_method_index_;
    wrong->ptr_sized_fields_.entry_point_from_jni_ = right->ptr_sized_fields_.entry_point_from_jni_;
    wrong->ptr_sized_fields_.entry_point_from_quick_compiled_code_ = right->ptr_sized_fields_.entry_point_from_quick_compiled_code_;
    wrong->ptr_sized_fields_.entry_point_from_interpreter_ = right->ptr_sized_fields_.entry_point_from_interpreter_;
}